/**
 * 🔍 异常检测服务
 * 检测各种类型的异常消费行为
 */

const db = require('../config/database');
const { calculateStats, calculateZScore } = require('../utils/stats');

class AnomalyDetector {
  /**
   * 检测所有异常
   */
  static async detectAllAnomalies(userId, bookId, recordId) {
    const anomalies = [];

    try {
      // 1. 大额异常检测
      const amountAnomaly = await this.detectAmountAnomaly(userId, bookId, recordId);
      if (amountAnomaly) anomalies.push(amountAnomaly);

      // 2. 频率异常检测
      const frequencyAnomaly = await this.detectFrequencyAnomaly(userId, bookId, recordId);
      if (frequencyAnomaly) anomalies.push(frequencyAnomaly);

      // 3. 时间异常检测
      const timeAnomaly = await this.detectTimeAnomaly(userId, bookId, recordId);
      if (timeAnomaly) anomalies.push(timeAnomaly);

      // 4. 模式异常检测
      const patternAnomaly = await this.detectPatternAnomaly(userId, bookId, recordId);
      if (patternAnomaly) anomalies.push(patternAnomaly);

    } catch (error) {
      console.error('异常检测失败:', error);
    }

    return anomalies;
  }

  /**
   * 大额异常检测（基于统计学）
   */
  static async detectAmountAnomaly(userId, bookId, recordId) {
    try {
      // 获取当前记录
      const [records] = await db.query(
        'SELECT * FROM records WHERE record_id = ? AND is_deleted != 1',
        [recordId]
      );
      
      if (!records || records.length === 0) return null;
      const record = records[0];
      
      if (record.type !== 'expense') return null;

      // 获取历史30天同类别消费
      const [historicalRecords] = await db.query(`
        SELECT amount FROM records
        WHERE user_id = ? AND book_id = ? 
          AND category = ? AND type = 'expense'
          AND is_deleted != 1
          AND date >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
          AND record_id != ?
        ORDER BY date DESC
        LIMIT 100
      `, [userId, bookId, record.category, recordId]);

      if (historicalRecords.length < 5) return null; // 数据不足

      // 计算统计量
      const amounts = historicalRecords.map(r => parseFloat(r.amount));
      const stats = calculateStats(amounts);
      
      // Z-Score 方法：超过2个标准差视为异常
      const zScore = calculateZScore(parseFloat(record.amount), stats.mean, stats.stdDev);
      
      if (Math.abs(zScore) > 2) {
        const severity = Math.abs(zScore) > 3 ? 'high' : 'medium';
        
        return {
          record_id: recordId,
          anomaly_type: 'amount',
          severity,
          description: `本笔消费￥${record.amount}，超过近30天该类别平均消费￥${stats.mean.toFixed(2)}的${Math.abs(zScore).toFixed(1)}倍标准差`,
          detected_value: parseFloat(record.amount),
          expected_value: stats.mean,
          confidence: Math.min(95, Math.abs(zScore) * 30)
        };
      }

      return null;
    } catch (error) {
      console.error('大额异常检测失败:', error);
      return null;
    }
  }

  /**
   * 频率异常检测
   */
  static async detectFrequencyAnomaly(userId, bookId, recordId) {
    try {
      const [record] = await db.query(
        'SELECT * FROM records WHERE record_id = ? AND is_deleted != 1',
        [recordId]
      );
      
      if (!record || record.length === 0) return null;

      const remark = record[0].remark || '';
      if (!remark) return null;
      
      // 统计今天相似描述的消费次数
      const [todayCount] = await db.query(`
        SELECT COUNT(*) as count FROM records
        WHERE user_id = ? AND book_id = ?
          AND remark LIKE ?
          AND DATE(date) = DATE(?)
          AND is_deleted != 1
      `, [userId, bookId, `%${remark}%`, record[0].date]);

      // 如果今天在同一商户/类型消费超过3次
      if (todayCount[0].count >= 3) {
        return {
          record_id: recordId,
          anomaly_type: 'frequency',
          severity: 'medium',
          description: `今天在「${remark}」已消费${todayCount[0].count}次，频率较高`,
          detected_value: todayCount[0].count,
          expected_value: 1,
          confidence: 75
        };
      }

      return null;
    } catch (error) {
      console.error('频率异常检测失败:', error);
      return null;
    }
  }

  /**
   * 时间异常检测
   */
  static async detectTimeAnomaly(userId, bookId, recordId) {
    try {
      const [record] = await db.query(
        'SELECT * FROM records WHERE record_id = ? AND is_deleted != 1',
        [recordId]
      );
      
      if (!record || record.length === 0) return null;

      const recordDate = new Date(record[0].date);
      const hour = recordDate.getHours();

      // 深夜消费（0-5点）
      if (hour >= 0 && hour < 5) {
        return {
          record_id: recordId,
          anomaly_type: 'time',
          severity: 'low',
          description: `深夜${hour}点消费，请注意消费习惯`,
          detected_value: hour,
          expected_value: 12,
          confidence: 60
        };
      }

      return null;
    } catch (error) {
      console.error('时间异常检测失败:', error);
      return null;
    }
  }

  /**
   * 模式异常检测
   */
  static async detectPatternAnomaly(userId, bookId, recordId) {
    try {
      // 检测短时间内多笔小额消费（可能是盗刷）
      const [record] = await db.query(
        'SELECT * FROM records WHERE record_id = ? AND is_deleted != 1',
        [recordId]
      );
      
      if (!record || record.length === 0) return null;

      const [recentRecords] = await db.query(`
        SELECT COUNT(*) as count, SUM(amount) as total
        FROM records
        WHERE user_id = ? AND book_id = ?
          AND date >= DATE_SUB(?, INTERVAL 30 MINUTE)
          AND type = 'expense'
          AND is_deleted != 1
      `, [userId, bookId, record[0].date]);

      // 30分钟内5笔以上小额消费
      const avgAmount = recentRecords[0].count > 0 ? recentRecords[0].total / recentRecords[0].count : 0;
      
      if (recentRecords[0].count >= 5 && avgAmount < 50) {
        return {
          record_id: recordId,
          anomaly_type: 'pattern',
          severity: 'high',
          description: `30分钟内检测到${recentRecords[0].count}笔小额消费，请确认是否为本人操作`,
          detected_value: recentRecords[0].count,
          expected_value: 1,
          confidence: 85
        };
      }

      return null;
    } catch (error) {
      console.error('模式异常检测失败:', error);
      return null;
    }
  }

  /**
   * 保存异常记录
   */
  static async saveAnomalies(userId, bookId, anomalies) {
    if (!anomalies || anomalies.length === 0) return;

    try {
      for (const anomaly of anomalies) {
        // 检查是否已存在相同的异常记录
        const [existing] = await db.query(`
          SELECT id FROM anomaly_records
          WHERE user_id = ? AND book_id = ? AND record_id = ? 
            AND anomaly_type = ? AND status = 'pending'
        `, [userId, bookId, anomaly.record_id, anomaly.anomaly_type]);

        if (existing.length === 0) {
          await db.query(`
            INSERT INTO anomaly_records 
            (user_id, book_id, record_id, anomaly_type, severity, description, 
             detected_value, expected_value, confidence)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
          `, [
            userId, bookId, anomaly.record_id, anomaly.anomaly_type,
            anomaly.severity, anomaly.description, anomaly.detected_value,
            anomaly.expected_value, anomaly.confidence
          ]);
        }
      }
    } catch (error) {
      console.error('保存异常记录失败:', error);
      throw error;
    }
  }

  /**
   * 获取待处理的异常
   */
  static async getPendingAnomalies(userId, bookId, limit = 20) {
    try {
      const [anomalies] = await db.query(`
        SELECT a.*, r.description, r.amount, r.date
        FROM anomaly_records a
        JOIN records r ON a.record_id = r.record_id
        WHERE a.user_id = ? AND a.book_id = ? AND a.status = 'pending'
        ORDER BY a.detected_at DESC
        LIMIT ?
      `, [userId, bookId, limit]);

      return anomalies;
    } catch (error) {
      console.error('获取异常记录失败:', error);
      throw error;
    }
  }

  /**
   * 更新异常状态
   */
  static async updateAnomalyStatus(anomalyId, userId, action) {
    try {
      await db.query(`
        UPDATE anomaly_records
        SET status = ?, user_action = ?, updated_at = NOW()
        WHERE id = ? AND user_id = ?
      `, [action, action, anomalyId, userId]);

      return true;
    } catch (error) {
      console.error('更新异常状态失败:', error);
      throw error;
    }
  }
}

module.exports = AnomalyDetector;

